import {
	createConnection,
	TextDocuments,
	ProposedFeatures,
	InitializeParams,
	CompletionItem,
	CompletionItemKind,
	TextDocumentPositionParams,
	TextDocumentSyncKind,
	InitializeResult,
	DidChangeConfigurationNotification,
	Range,
	Position
} from 'vscode-languageserver/node';

import { TextDocument } from 'vscode-languageserver-textdocument';
import * as path from 'path';
import * as fs from 'fs';
import postcss from 'postcss';

import className from './suggestionCfg/className';


const connection = createConnection(ProposedFeatures.all);

const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);

let hasConfigurationCapability = false;
let hasWorkspaceFolderCapability = false;
let pathRoot = '';
let pathUri = '';
connection.onInitialize((params: InitializeParams) => {
	const capabilities = params.capabilities;
	if(params.rootPath){
		pathRoot = params.rootPath;
	}
	if(params.rootUri){
		pathUri = params.rootUri;
	}
	hasConfigurationCapability = !!(
		capabilities.workspace && !!capabilities.workspace.configuration
	);
	hasWorkspaceFolderCapability = !!(
		capabilities.workspace && !!capabilities.workspace.workspaceFolders
	);
	const result: InitializeResult = {
		capabilities: {
			textDocumentSync: TextDocumentSyncKind.Incremental,
			// 声明提供代码补全功能
			completionProvider: {
				resolveProvider: true,
				triggerCharacters: [' ']
			}
		}
	};
	if (hasWorkspaceFolderCapability) {
		result.capabilities.workspace = {
			workspaceFolders: {
				supported: true
			}
		};
	}
	return result;
});

connection.onInitialized(() => {
	if (hasConfigurationCapability) {
		// Register for all configuration changes.
		connection.client.register(DidChangeConfigurationNotification.type, undefined);
	}
	if (hasWorkspaceFolderCapability) {
		connection.workspace.onDidChangeWorkspaceFolders(_event => {
			connection.console.log('Workspace folder change event received.');
		});
	}
});

const classArray:CompletionItem[] = className.map((i,idx)=>{
	return {
		...i,
		data:idx,
		kind: CompletionItemKind.Snippet,
		documentation: 'css常用类名'
	};
});

// 使用文件相对路径做键名存储格式化好的CompletionItem项
const cssProvideMap = new Map<string,CompletionItem[]>();


// 获取用户配置样式文件
const getCssFile = async () => {
	const { url } = await connection.workspace.getConfiguration({section:'cssTips'});
	
	if(Array.isArray(url)){
		url.forEach( p=>{
			if(typeof p === 'string' && /.css$/.test(p)){
				parseCss(p);
			}
		});
	}
};
// 解析css文件
const parseCss = (url:string) => {
	const allPath = path.resolve(pathRoot,url);
	fs.readFile(allPath,'utf-8',(err,data)=>{
		if(err) {return;};
		const { nodes } = postcss.parse(data);
		const arr:CompletionItem[] = [];
		let comment = '';
		nodes.forEach(i=>{
			// 如果是注释信息暂存
			if(i.type === 'comment'){
				comment = '/* ' + i.text + ' */';
			}
			if(i.type === 'rule'){
				const prop:string[] = [];
				// 循环找出类名下的样式属性拼装成字符串
				i.nodes.forEach(d=>{
					if(d.type === 'decl'){
						prop.push('\t' + d.prop + ' : ' + d.value + ';');
					}
				});
				// 筛选出类名
				i.selectors.forEach(k=>{
					if(/^\..*/.test(k)){
						arr.push({
							label: k.slice(1),
							data: Math.random(),
							kind: CompletionItemKind.Field,
							detail: url,
							documentation:{
								kind: 'markdown',
								value: [
									comment, // 注释信息拼接到此处markdown 中
									'```css',
									k,
									'{',
									...prop,
									'}',
									'```'
								].join('\n')
							}
						});
						comment = '';
					}
				});
			} 
		});
		cssProvideMap.set(url, arr);
		concatArr();
	});
};

connection.onInitialized(() => {
	if (hasConfigurationCapability) {
		// Register for all configuration changes. 
		connection.client.register(DidChangeConfigurationNotification.type, undefined);
	}
	getCssFile();
});


connection.onDidChangeConfiguration( change=>{
	cssProvideMap.clear();
	getCssFile();
});

documents.onDidSave(async (pa)=>{
	const { url } = await connection.workspace.getConfiguration({section:'cssTips'});
	const u = pa.document.uri;
	// console.log('u', u);
	// console.log('url', url);
	if(Array.isArray(url)){
		url.forEach( p=>{
			if(typeof p === 'string' && u.includes(p.replace(/^\.?\/?/,''))){
				parseCss(p);
			}
		});
	}
});

documents.onDidClose(e => {
	console.log('关闭文档链接');
});

documents.onWillSave(e=>{
	console.log('e:文件将要保存', e);
	return undefined;
});




let providList: CompletionItem[] = [];

const concatArr = () => {
	let cp: CompletionItem[] = [];
	Array.from(cssProvideMap.values()).forEach(i=> cp.push(...i));
	providList = [...classArray,...cp];
};

concatArr();

connection.onCompletion(
	(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
		let res:CompletionItem[] = [];
		const { position:{character,line}, textDocument:{uri} } = _textDocumentPosition;
		const range = Range.create(Position.create(line,0),Position.create(line,character));
		// 找到光标所在行字符串
		const text = documents.get(uri)?.getText().split('\n')[line] || '';
		// console.log('text:',text);
		// 光标前半段字符串
		const t1 = text.slice(0,character);
		// 光标后半段
		const t2 = text.slice(character);
		// 前半段反向查找 class=` 或 class=’ 或 class=" 
		const r1 = /\bclass=(("[^"]*)|('[^']*)|(`[^`]*))$/;
		const c1 = r1.exec(t1);
		// 确认使用的那种字符串符号
		const sy = c1?.[0].slice(-1);
		// 如果sy存在并且后半段字符串包含sy则说明光标所处位置在class=''属性值内 触发class建议
		if(sy && t2.indexOf(sy) !== -1){
			// let cp: CompletionItem[] = [];
			// Array.from(cssProvideMap.values()).forEach(i=> cp.push(...i));
			// res = [...classArray,...cp];
			res = providList;
		}
		return res;
	}
);


connection.onCompletionResolve(
	(item: CompletionItem): CompletionItem => {
		return item;
	}
);


documents.listen(connection);

connection.listen();
